package streaming.control;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Format;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.ProcessorModel;
import javax.media.RealizeCompleteEvent;
import javax.media.StartEvent;
import javax.media.StopEvent;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


/**
 * Klasa kontrolise zivotni ciklus <code>Player</code> objekta, koriscenog za prikaz videa. 
 * Omogucava dobijanje vizuelne komponente i bez potrebe da <code>player</code> bude u 
 * <code>Realized</code> stanju.
 * 
 * Implementira <code>ActionListener</code>, i time pruza mogucnost da bilo koja komponenta koja generise
 * <code>ActionEvent</code>, moze da kontrolise prikaz videa (u vidu prekidaca - ima videa/nema videa)
 * 
 * @author UrosKrkic & Radivoje Popovic
 *
 */

public class VideoControl implements Control, ControllerListener, ActionListener{

	/**
	 * je objekat kojim upravlja <code>VideoControl</code>.
	 */
	private Player player;
	
	/**
	 * vizuelna komponenta kontrole.
	 */
	private JPanel videoComponent;
	
	/**
	 * indikator da su dimenzije prikaza prilagodjene komponenti za nadzor
	 */
	private boolean monitor = false;
	
	/**
	 * dimenzije komponente za nadzor
	 */
	private static final Rectangle MONITOR = new Rectangle(0, 0, 128, 96);
	
	/**
	 * dimenzije komponente za streaming
	 */
	private static final Rectangle STREAMING = new Rectangle(0, 0, 176, 144);
	
	
	/**
	 * Kreira novi <code>VideoControl</code> objekat bez pridruzenog <code>Player</code> objekta.
	 * 
	 * @param monitor indikator da su dimenzije prikaza prilagodjene komponenti za nadzor
	 * 
	 */
	public VideoControl(boolean monitor) {
		videoComponent = new JPanel();
		this.monitor = monitor;
		generateDummyScreen();
	}
	
	/**
	 * Kreira novi <code>VideoControl</code> i pridruzuje mu <code>Player</code> objekat,
	 * cijim ce zivotnim ciklusom upravljati.
	 * 
	 * @param monitor indikator da su dimenzije prikaza prilagodjene komponenti za nadzor.
	 * @param player  je <code>Player</code> objekat kojim upravlja <code>VideoControl</code>.
	 */
	public VideoControl(Player player, boolean monitor) {
		this(monitor);
		this.player = player;
		this.player.addControllerListener(this);
		this.player.realize();


	}

	/**
	 * Kreira novi <code>VideoControl</code> objekat.
	 * <br>
	 * NOTE: <code>dataSource</code> mora biti aktivan prije upotrebe u konstruktoru.
	 * 
	 * @param monitor indikator da su dimenzije prikaza prilagodjene komponenti za nadzor.
	 * @param dataSource se koristi za kreiranje novog <code>Player</code> objekta, cijim ce 
	 * zivotnim ciklusom upravljati.
	 */
	public VideoControl(DataSource dataSource, boolean monitor) throws IOException, NoPlayerException{
		this(Manager.createPlayer(dataSource), monitor);

	}

	
	/**
	 * Odredjuje izgled vizuelne komponente kad video nije dostupan
	 */
	private void generateDummyScreen(){
		videoComponent.removeAll();
		videoComponent.setLayout(null);
		JLabel label;
		if(monitor){
			label = new JLabel(utils.ImageCreator.createImageIcon(this.getClass(), "images/nocallsanscam128.png"));
			label.setBounds(MONITOR);
		}
		else{
			label = new JLabel(utils.ImageCreator.createImageIcon(this.getClass(), "images/nocallsanscam.png"));
			label.setBounds(STREAMING);
		}
		videoComponent.add(label);
		videoComponent.repaint();

	}




	/**
	 * 
	 * @return vizuelnu komponentu (video, ako je dostupan, u suprotnom, dummy screen)
	 */
	@Override
	public JComponent getVideoComponent(){
		return videoComponent;
	}


	@Override
	public void controllerUpdate(ControllerEvent e) {
		if(e instanceof RealizeCompleteEvent){
			if(e.getSource().equals(player)){
				player.prefetch();
			}
		}
		else if(e instanceof PrefetchCompleteEvent){
			if(e.getSource().equals(player)){
				player.start();
			}
		}
		else if(e instanceof StartEvent){
			if(e.getSource().equals(player)){
				setVideo();
			}
		}
		else if(e instanceof StopEvent){
			if(e.getSource().equals(player)){
				generateDummyScreen();
			}
		}
	}

	/**
	 * Podesava vizuelnu komponentu tako da prikazuje video.
	 */
	private void setVideo() {
		videoComponent.removeAll();
		videoComponent.setLayout(null);
		if(isMonitor()){
			player.getVisualComponent().setBounds(MONITOR);
		}
		else{
			player.getVisualComponent().setBounds(STREAMING);
		}
		videoComponent.add(player.getVisualComponent());
		videoComponent.repaint();
		videoComponent.revalidate();
		SwingUtilities.updateComponentTreeUI(videoComponent);
	}

	
	
	public Player getPlayer() {
		return player;
	}

	/**
	 * Oslobadja trenutni <code>player</code>, ako postoji, i prijavljuje novi. 
	 * @param player 
	 */
	@Override
	public void setPlayer(Player player) {
		if(this.player != null){
			this.player.stop();
			this.player.close();
			this.player.removeControllerListener(this);
		}
		this.player = player;
		this.player.addControllerListener(this);
		this.player.realize();

	}

	/**
	 * Oslobadja trenutni <code>player</code>, ako postoji, i prijavljuje novi, kreiran od <code>dataSource</code>-a. 
	 * @param ds 
	 */
	@Override
	public void setDataSource(DataSource dataSource) throws NoPlayerException, IOException {
		setPlayer(Manager.createPlayer(dataSource));
	}

	
	public boolean isMonitor() {
		return monitor;
	}

	public void setMonitor(boolean monitor) {
		this.monitor = monitor;
//		generateDummyScreen();
	}

	public static void main(String[] args) {

//		VideoControl vc = new VideoControl();
//		JFrame frame = new JFrame();
//		frame.setBounds(0, 0, 300, 300);
//		frame.getContentPane().add(vc.getVideoComponent());
//		frame.setVisible(true);

//		ProcessorModel model = new ProcessorModel(
//		new Format[]{new VideoFormat(VideoFormat.H263)}, 
//		new ContentDescriptor(ContentDescriptor.RAW));

//		Processor captureProcessor;
//		try {
//		captureProcessor = Manager.createRealizedProcessor(model);
//		vc.setDataSource(captureProcessor.getDataOutput());
//		captureProcessor.start();
//		} catch (Exception e) {	} 

		VideoControl vc2 = new VideoControl(false);
		JFrame frame2 = new JFrame();
		frame2.setBounds(0, 300, 300, 300);
//		frame2.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
		frame2.getContentPane().add(vc2.getVideoComponent());
		frame2.setVisible(true);

		ProcessorModel model2 = new ProcessorModel(
				new Format[]{new VideoFormat(VideoFormat.H263)}, 
				new ContentDescriptor(ContentDescriptor.RAW));

		Processor captureProcessor2;
		try {
			captureProcessor2 = Manager.createRealizedProcessor(model2);
//			vc2.setMonitor(true);
			vc2.setDataSource(captureProcessor2.getDataOutput());
			captureProcessor2.start();
		} catch (Exception e) {	} 


	}

	public void stop() {
		if(player != null)
			player.stop();
	}


	private void pause() {
		if(player != null)
			player.stop();
	}

	private void resume() {
		if(player != null)
			player.realize();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() instanceof JCheckBox){
			if(((JCheckBox)e.getSource()).isSelected()){
				resume();
			}
			else{
				pause();
			}
		}
	}



}
